import { flexRender } from '@tanstack/react-table';
import cx from 'classnames';
import React, { useContext, useMemo } from 'react';
import Tooltip from '../../../Tooltip';
import { SvgEdit } from '../../Svg';
import { disabledResizeColumn } from '../../config';
import { UPDATE_COLUMNSORTING } from '../../context/table';
import { useDraggableColumn } from '../../utils/useDraggable';

import type { Header, Table } from '@tanstack/react-table';
import type { Context } from '../../context/table';
import type { Align, AnyObject, ColumnMeta, Size, Sort } from '../../type';

export interface Props<T extends AnyObject, Context = any> {
  bordered?: boolean;
  width?: number;
  align?: Align;
  size?: Size;
  className?: string;
  prefixCls?: string;
  isCanDrag?: boolean;
  isCanResizeColumn?: boolean;
  style?: React.CSSProperties;
  header: Header<T, unknown>;
  table: Table<T>;
  context: React.Context<Context>;
}
const sortInfo: { [key in Sort]: string } = {
  asce: '点击升序',
  desc: '点击降序',
  none: '取消排序',
};
function TableHeader<T extends AnyObject>(props: Props<T>) {
  const {
    context,
    bordered,
    align,
    size,
    className,
    prefixCls,
    header,
    table,
    isCanDrag,
    isCanResizeColumn,
    style,
  } = props;
  const {
    table: { isCanEdit, columnSorting },
    dispatch,
  } = useContext<Context<T>>(context);
  const { dropRef, dragRef, previewRef, isDragging } = useDraggableColumn({
    header,
    table,
  });
  const { column } = header;
  const columnSize = column.getSize();
  const columnMeta: ColumnMeta<T> = column.columnDef.meta || {};

  const isShowRule = useMemo(() => {
    const { rule } = columnMeta;
    return (
      isCanEdit && rule && !!rule.length && rule.some((item) => item.required)
    );
  }, [columnMeta.rule, isCanEdit]);

  const sortWays = useMemo(() => Object.keys(sortInfo) as Sort[], [sortInfo]);
  const isShowSorter = useMemo(
    () => !isCanEdit && !!columnMeta.sorter,
    [columnMeta.sorter, isCanEdit],
  );
  const curSort = useMemo(
    () => columnSorting[header.id] || 'none',
    [header.id, columnSorting],
  );
  const nextSort = useMemo(() => {
    const curSortIndex = sortWays.findIndex((v) => v === curSort);
    const nextSortIndex =
      curSortIndex + 1 < sortWays.length ? curSortIndex + 1 : 0;
    return sortWays[nextSortIndex];
  }, [sortWays, curSort, header.id]);
  const tooltip = useMemo(
    () => (isShowSorter ? sortInfo[nextSort] : ''),
    [isShowSorter, sortInfo, nextSort],
  );
  const isSorting = useMemo(
    () => ['asce', 'desc'].includes(curSort),
    [curSort],
  );

  const thProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {
      key: header.id,
      style: {
        ...style,
        width: isNaN(header.getSize()) ? 'auto' : header.getSize(),
      },
    };
    if (isCanDrag) {
      props.style.opacity = isDragging ? 0.5 : 1;
      props.ref = dropRef;
    }

    return props;
  }, [
    isCanDrag,
    isDragging,
    isCanResizeColumn,
    dropRef,
    header,
    columnSize,
    style,
  ]);
  const thContentProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {};
    if (isCanDrag) {
      props.ref = previewRef;
    }
    return props;
  }, [isCanDrag, previewRef]);
  const thRenderProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {};
    if (isCanDrag) {
      props.ref = dragRef;
    }
    return props;
  }, [isCanDrag, dragRef]);

  const setSort = (sort: Sort) => {
    dispatch({
      type: UPDATE_COLUMNSORTING,
      payload: { ...columnSorting, [header.id]: sort },
    });
  };

  return (
    <Tooltip title={tooltip}>
      <div
        role="columnheader"
        id={header.id}
        className={cx(`${prefixCls}-th`, size, {
          bordered,
          className,
          [`${prefixCls}-th-sorted`]: isSorting,
        })}
        {...thProps}
        onClick={() => isShowSorter && setSort(nextSort)}
      >
        <div className={`${prefixCls}-th-content`} {...thContentProps}>
          <div
            className={cx(`${prefixCls}-th-render`, align)}
            {...thRenderProps}
          >
            {isShowRule && <div className={`${prefixCls}-th-rule`}>*</div>}
            <div className={`${prefixCls}-th-text`}>
              {header.isPlaceholder
                ? null
                : flexRender(column.columnDef.header, header.getContext())}
            </div>
            {isCanEdit && !!columnMeta.editType && !columnMeta.parent && (
              <div className={`${prefixCls}-th-edit`}>
                <SvgEdit />
              </div>
            )}
            {isShowSorter && (
              <div className={`${prefixCls}-th-sorter`}>
                <div
                  className={cx(`${prefixCls}-th-asce`, {
                    [`asce-active`]: curSort === 'asce',
                  })}
                ></div>
                <div
                  className={cx(`${prefixCls}-th-desc`, {
                    [`desc-active`]: curSort === 'desc',
                  })}
                ></div>
              </div>
            )}
          </div>
          {isCanResizeColumn && !disabledResizeColumn.includes(header.id) && (
            <div
              className={cx('resizer', `${prefixCls}-th-resizer`, {
                isResizing: column.getIsResizing(),
              })}
              onMouseDown={header.getResizeHandler()}
              onTouchStart={header.getResizeHandler()}
            />
          )}
        </div>
      </div>
    </Tooltip>
  );
}

export default TableHeader;
